﻿using Bio;
using Bio.IO.FastA;
using Candy.Infrastructure;
using Candy.Model;
using Candy.Web.Data;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace Candy.ViewModel
{
    public class GenesViewModel : CandyViewModelBase
    {
        private bool _isBusy;
        public bool IsBusy
        {
            get
            {
                return _isBusy;
            }
            set
            {
                _isBusy = value;
                RaisePropertyChanged("IsBusy");
                if (value)
                    base.ReportProgress();
                else
                    base.FinishProgress();

            }
        }

        private ObservableCollection<GeneEditViewModel> _genes;
        public ObservableCollection<GeneEditViewModel> Genes
        {
            get
            {
                return _genes;
            }
            set
            {
                _genes = value;
                RaisePropertyChanged("Genes");
            }
        }


        private ObservableCollection<GeneEditViewModel> _selectedGenes = new ObservableCollection<GeneEditViewModel>();
        public ObservableCollection<GeneEditViewModel> SelectedGenes
        {
            get
            {
                return _selectedGenes;
            }

        }


        private GeneEditViewModel _selectedGene;
        public GeneEditViewModel SelectedGene
        {
            get
            {
                return _selectedGene;
            }
            set
            {
                _selectedGene = value;
                RaisePropertyChanged("SelectedGene");
                if (_selectedGene != null)
                    _selectedGene.LoadAnnotations.Execute(null);
            }
        }


        private FamilyEditViewModel _selectedFamily;
        public FamilyEditViewModel SelectedFamily
        {
            get
            {
                return _selectedFamily;
            }
            set
            {
                if (value != null)
                {
                    if (_selectedFamily != null)
                    {
                        _selectedFamily.Entity.Items.EntityAdded -= Items_EntityAdded;
                        _selectedFamily.Entity.Items.EntityRemoved -= Items_EntityRemoved;
                    }

                    _selectedFamily = value;
                    RaisePropertyChanged("SelectedFamily");
                    LoadFamilyGenes.Execute(value);
                    CreateGene.RaiseCanExecuteChanged();
                    if (_selectedFamily != null)
                    {
                        _selectedFamily.Entity.Items.EntityAdded += Items_EntityAdded;
                        _selectedFamily.Entity.Items.EntityRemoved += Items_EntityRemoved;
                    }
                }
            }
        }

        void Items_EntityRemoved(object sender, System.ServiceModel.DomainServices.Client.EntityCollectionChangedEventArgs<GeneDto> e)
        {
            var toRem = Genes.SingleOrDefault(x => x.Entity == e.Entity);
            Genes.Remove(toRem);
        }

        void Items_EntityAdded(object sender, System.ServiceModel.DomainServices.Client.EntityCollectionChangedEventArgs<GeneDto> e)
        {
            GeneEditViewModel vm = new GeneEditViewModel(_dataService, _navigationService, e.Entity);
            Genes.Add(vm);
        }

        IDataService _dataService;
        INavigationService _navigationService;
         public GenesViewModel(IDataService dataService, INavigationService navigationService)
        {
 
            _dataService = dataService;
            _navigationService = navigationService;

            MessengerInstance.Register<NotificationMessage<FamilyEditViewModel>>(this, msg =>
                {
                    if (msg.Notification == ViewModelMessageTypes.SelectFamily)
                        SelectedFamily = msg.Content;
                });

            if (IsInDesignMode)
            {

                try
                {
                    SelectedGene = new GeneEditViewModel(_dataService, _navigationService, new GeneDto
                        {
                            Name = "WEWE_ASAS",
                            GeneIdentifier = "ASDA_SADS",
                            Family = new FamilyDto { Name = "SDSDD sd" },
                            Genotype = new GenotypeDto { Name = "Arabidosis thaliana" },
                            
                        });
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    MessageBox.Show(ex.StackTrace);
                }

            }

        }


        private RelayCommand<FamilyEditViewModel> _loadFamilyGenes;
        public RelayCommand<FamilyEditViewModel> LoadFamilyGenes
        {
            get
            {
                return _loadFamilyGenes ?? (_loadFamilyGenes = new RelayCommand<FamilyEditViewModel>(ExecLoadFamilyGenes, CanLoadFamilyGenes));
            }
        }

        /// <summary>
        /// Checks whether the LoadFamilyGenes command is executable
        /// </summary>
        private bool CanLoadFamilyGenes(FamilyEditViewModel val)
        {
            return true;
        }

        /// <summary>
        /// Executes the LoadFamilyGenes command 
        /// </summary>
        private void ExecLoadFamilyGenes(FamilyEditViewModel val)
        {
            if (val == null)
                Genes = new ObservableCollection<GeneEditViewModel>();
            else
            {
                Genes = new ObservableCollection<GeneEditViewModel>();
                LoadGenesRecursive(val.Entity);
                SelectedGene = Genes.FirstOrDefault();
            }
        }

        private void LoadGenesRecursive(FamilyDto family)
        {
            foreach (var g in family.Items)
            {
                _genes.Add(new GeneEditViewModel(_dataService, _navigationService, g));
            }
            foreach (var item in family.SubFamilies)
            {
                LoadGenesRecursive(item);
            }
        }



        private RelayCommand<object> _selectGenes;
        public RelayCommand<object> SelectGenes
        {
            get
            {
                return _selectGenes ?? (_selectGenes = new RelayCommand<object>(ExecSelectGenes, CanSelectGenes));
            }
        }

        /// <summary>
        /// Checks whether the SelectGenes command is executable
        /// </summary>
        private bool CanSelectGenes(object val)
        {
            return true && !IsInDesignMode;
        }

        /// <summary>
        /// Executes the SelectGenes command 
        /// </summary>
        private void ExecSelectGenes(object val)
        {

            if (val != null && val is SelectionChangedEventArgs)
            {
                SelectionChangedEventArgs args = (SelectionChangedEventArgs)val;


                foreach (var item in args.AddedItems)
                {
                    SelectedGenes.Add((GeneEditViewModel)item);
                }
                foreach (var item in args.RemovedItems)
                {
                    SelectedGenes.Remove((GeneEditViewModel)item);
                }
                if (args.AddedItems.Count > 0)
                    SelectedGene = (GeneEditViewModel)args.AddedItems[0];
                else
                    SelectedGene = SelectedGenes.FirstOrDefault();
            }
            else if (val != null && val is GeneDto)
            {
              
                SelectedGenes.Clear();
                SelectedGene = null;
                GeneEditViewModel vm = Genes.FirstOrDefault(x => x.Entity == val);
                if (vm == null)
                {
                    //not in current family
                    vm = new GeneEditViewModel(_dataService, _navigationService, val as GeneDto);
                }
                SelectedGenes.Add(vm);
                SelectedGene = vm;
            }
            else if (val != null && val is GenesViewModel)
            {

                SelectedGenes.Clear();
                SelectedGene = null;
                GeneEditViewModel vm = val as GeneEditViewModel;
                if (vm != null)
                {
                    SelectedGenes.Add(vm);
                    SelectedGene = vm;
                }
            }
            if (_selectedGenes != null)
                _selectedGenes.CollectionChanged += (s, a) => { EditGene.RaiseCanExecuteChanged(); DeleteGenes.RaiseCanExecuteChanged(); };
            EditGene.RaiseCanExecuteChanged();
            DeleteGenes.RaiseCanExecuteChanged();
            RaisePropertyChanged("SelectedGenes");
        }




        private RelayCommand _createGene;
        public RelayCommand CreateGene
        {
            get
            {
                return _createGene ?? (_createGene = new RelayCommand(ExecCreateGene, CanCreateGene));
            }
        }

        /// <summary>
        /// Checks whether the CreateFamily command is executable
        /// </summary>
        private bool CanCreateGene()
        {
            return SelectedFamily != null;
        }

        /// <summary>
        /// Executes the CreateFamily command 
        /// </summary>
        /// <param name="parentFamily">The parent family</param>
        private void ExecCreateGene()
        {
            var vm = new GeneEditViewModel(_dataService, _navigationService, new Web.Data.GeneDto() { AutogeneratedName = true, ScientificRelevance = 1, FamilyId = SelectedFamily.Entity.Id, EntryType = GeneEntryType.bait });
            vm.Entity.ProjectId = _dataService.LoadedProject.Id;
            vm.Edit.Execute(null);
            _navigationService.ShowGeneEditor(vm);
        }




        private RelayCommand _editGene;
        public RelayCommand EditGene
        {
            get
            {
                return _editGene ?? (_editGene = new RelayCommand(ExecEditGene, CanEditGene));
            }
        }

        /// <summary>
        /// Checks whether the EditGene command is executable
        /// </summary>
        private bool CanEditGene()
        {
            return SelectedGenes != null && SelectedGenes.Count > 0;
        }

        /// <summary>
        /// Executes the EditGene command 
        /// </summary>
        private void ExecEditGene()
        {
            SelectedGenes.First().Edit.Execute(null);
            _navigationService.ShowGeneEditor(SelectedGenes.First());
        }



        private RelayCommand _deleteGened;
        public RelayCommand DeleteGenes
        {
            get
            {
                return _deleteGened ?? (_deleteGened = new RelayCommand(ExecDeleteGenes, CanDeleteGenes));
            }
        }

        /// <summary>
        /// Checks whether the DeleteGenes command is executable
        /// </summary>
        private bool CanDeleteGenes()
        {
            return SelectedGenes != null && SelectedGenes.Count > 0;
        }

        /// <summary>
        /// Executes the DeleteGenes command 
        /// </summary>
        private void ExecDeleteGenes()
        {
            base.ResetError();
            string confirmation = "";
            if (SelectedGenes.Count == 1)
                confirmation = "You are about to delete gene '" + SelectedGenes.First().Entity.Name + "'";
            else
                confirmation = "You are about to delete " + SelectedGenes.Count + " genes.";
            base.ConfirmAction(doit =>
                {
                    if (doit)
                    {
                        IsBusy = true;

                        foreach (var item in SelectedGenes.ToList())
                        {
                            _dataService.Genes.Remove(item.Entity);

                        }
                        _dataService.SubmitAsync(op =>
                            {
                                IsBusy = false;
                                if (op.HasError)
                                {
                                    base.HandleDomainError(op, "Deleting gene(s) failed.");
                                }
                                else
                                {
                                    //
                                }
                            });
                    }
                }, confirmation);

        }




        private RelayCommand _copyAsFasta;
        public RelayCommand CopyAsFasta
        {
            get
            {
                return _copyAsFasta ?? (_copyAsFasta = new RelayCommand(ExecCopyAsFasta, CanCopyAsFasta));
            }
        }

        /// <summary>
        /// Checks whether the CopyAsFasta command is executable
        /// </summary>
        private bool CanCopyAsFasta()
        {
            return true;
        }

        /// <summary>
        /// Executes the CopyAsFasta command 
        /// </summary>
        private void ExecCopyAsFasta()
        {
            FastAFormatter formatter = new FastAFormatter();
            string text = "";
            foreach (var item in SelectedGenes.Where(x => !string.IsNullOrEmpty(x.Entity.ProteinSequence)))
            {
                ISequence seq = new Sequence(Alphabets.AmbiguousProtein, item.Entity.ProteinSequence);
                seq.ID = item.Entity.Name;
                text += formatter.Format(seq);

            }
            Clipboard.SetText(text);

        }


        private RelayCommand _moveSelectedGenes;
        public RelayCommand MoveSelectedGenes
        {
            get
            {
                return _moveSelectedGenes ?? (_moveSelectedGenes = new RelayCommand(ExecMoveSelectedGenes, CanMoveSelectedGenes));
            }
        }

        /// <summary>
        /// Checks whether the MoveSelectedGenes command is executable
        /// </summary>
        private bool CanMoveSelectedGenes()
        {
            return _selectedGenes != null && _selectedGenes.Count > 0;
        }

        /// <summary>
        /// Executes the MoveSelectedGenes command 
        /// </summary>
        private void ExecMoveSelectedGenes()
        {
            _navigationService.ShowMoveToFamily(_selectedGenes);
        }



    }
}
